﻿#region File and License Information
/*
<File>
	<Copyright>Copyright © 2007, Daniel Vaughan. All rights reserved.</Copyright>
	<License see="prj:///Documentation/License.txt"/>
	<Owner Name="Daniel Vaughan" Email="dbvaughan@gmail.com"/>
	<CreationDate>2008-11-03 23:32:33Z</CreationDate>
	<LastSubmissionDate>$Date: $</LastSubmissionDate>
	<Version>$Revision: $</Version>
</File>
*/
#endregion

using System;
using System.Threading;
using System.Windows;
using System.Windows.Threading;

using DanielVaughan.Concurrency;

namespace DanielVaughan
{
	/// <summary>
	/// Singleton class providing the default implementation 
	/// for the <see cref="ISynchronizationContext"/>, specifically for the UI thread.
	/// </summary>
	public class UISynchronizationContext : ISynchronizationContext
	{
        public Dispatcher RootVisualDispatcher;
		DispatcherSynchronizationContext context;
		Dispatcher dispatcher;
		
		#region Singleton implementation

		public static UISynchronizationContext instance;		
		/// <summary>
		/// Gets the singleton instance.
		/// </summary>
		/// <value>The current.</value>
		public static ISynchronizationContext Instance
		{
			get
			{
				return instance;
			}
		}
        public UISynchronizationContext(Dispatcher dispatcher)
        {
            this.dispatcher = dispatcher;
            context = new DispatcherSynchronizationContext(dispatcher);
        }
		UISynchronizationContext()
		{
			if (Application.Current.RootVisual != null)
			{
				dispatcher = Application.Current.RootVisual.Dispatcher;
				context = new DispatcherSynchronizationContext(dispatcher);
			}
		}

		#endregion

		public void Initialize()
		{
			if (Application.Current.RootVisual != null)
			{
				dispatcher = Application.Current.RootVisual.Dispatcher;
				context = new DispatcherSynchronizationContext(dispatcher);
			}
			else
			{
				throw new ConcurrencyException("Application.Instance.RootVisual should not be null. Use Initialize(Dispatcher) or leave initialization until after RootVisual is instantiated.");
			}
		}

		public void Initialize(Dispatcher dispatcher)
		{
			ArgumentValidator.EnsureNotNull(dispatcher, "dispatcher");
			this.dispatcher = dispatcher;
			context = new DispatcherSynchronizationContext(dispatcher);
		}

		public void InvokeAsynchronously(SendOrPostCallback callback, object state)
		{
			ArgumentValidator.EnsureNotNull(callback, "callback");

			context.Post(callback, state);
		}

		public void InvokeAsynchronously(Action action)
		{
			ArgumentValidator.EnsureNotNull(action, "action");

			if (dispatcher.CheckAccess())
			{
				action();
			}
			else
			{
				dispatcher.BeginInvoke(action);
			}
		}

		public void InvokeSynchronously(SendOrPostCallback callback, object state)
		{
			ArgumentValidator.EnsureNotNull(callback, "callback");

			context.Send(callback, state);
		}

		public void InvokeSynchronously(Action action)
		{
			ArgumentValidator.EnsureNotNull(action, "action");

			if (dispatcher.CheckAccess())
			{
				action();
			}
			else
			{
				context.Send(delegate { action(); }, null);
			}
		}

		public bool InvokeRequired
		{
			get
			{
				return !dispatcher.CheckAccess();
			}
		}
	}
}
